﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;
using LogLib;
using ComLib.ComType;
using System.IO;

namespace LaserMeasure
{
    public delegate void DataReceivedEventHandler(int result);

    public delegate void LaserErrorReceivedEventHandler(string error, int code);

    /// <summary>
    /// 传感器通信服务
    /// </summary>
    public class LaserService
    {
        /// <summary>
        /// 错误信息
        /// </summary>
        private string _error = "";
        public string Error
        {
            get { return _error; }
        }

        private LaserOption _option = new LaserOption();
        public LaserOption Option
        {
            get { return _option; }
        }

        public event DataReceivedEventHandler dataReceived;
        private void OnMeasuringUpdated(int result)
        {
            if (dataReceived != null)
            {
                dataReceived(result);
            }
        }

        public event LaserErrorReceivedEventHandler errorReceived;
        private void OnErrorReceived(string error, int code)
        {
            if (errorReceived != null)
            {
                errorReceived(error, code);
            }
        }

        public SerialPort serialPort;

        /// <summary>
        /// 判断串口是否打开
        /// </summary>
        public bool IsOpen
        {
            get
            {
                if (serialPort != null)
                {
                    return serialPort.IsOpen;
                }
                return false;
            }
        }

        private Thread thread = null;

        private bool _isMeasuring = false;
   
        /// <summary>
        /// 等待处理事件
        /// </summary>
        protected ManualResetEventSlim _waitEvent;

        public LaserService()
        {
            if (!File.Exists(_option.ConfigFilePath))
            {
                _option.Save();
            }         
            _option.Load();
            _waitEvent = new ManualResetEventSlim(false);
            serialPort = new SerialPort();
            serialPort.DataReceived += OnDataReceived;
            InitErrorMap();
        }

        /// <summary>
        /// 开始连续测量
        /// </summary>
        public void StartMeasuring()
        {
            Log.Write("开始连续测量...");
            serialPort.WriteLine("iACM");
        }

        /// <summary>
        /// 停止连续测量
        /// </summary>
        public void StopMeasuring()
        {
            Log.Write("停止连续测量高度...");
            serialPort.WriteLine("iHALT");
        }

        private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            while(serialPort.BytesToRead > 0)
            {
                string dataReceive = serialPort.ReadLine();
                //string dataReceive = Encoding.Default.GetString(readBuffer);
                Log.Write("Receive data form senor: " + dataReceive);
                int result = 0;
                if (TryParseMeasuredResult(dataReceive, out result))
                {
                    OnMeasuringUpdated(result);
                }              
            }         
        }

        public bool Open()
        {
            _error = "";          
            serialPort.BaudRate = _option.BaudRate; //9600
            serialPort.DataBits = _option.DataBit;
            serialPort.StopBits = _option.StopBit;
            serialPort.Parity = _option.Parity;
            serialPort.ReadTimeout = _option.ReadTimeout;
            serialPort.PortName = _option.ComNo;
            bool ret = true;
            try
            {
                serialPort.Open();
            }
            catch (Exception ex)
            {
                _error = ex.Message;
                Log.Write(ex.ToString());
                return false;
            }

            if (serialPort.IsOpen)
            {
                Log.Write("串口打开成功!");
                //StartWorking();
            }
            else
            {
                _error = "串口打开失败!";
                Log.Write(_error);
                ret = false;
            }
            return ret;         
        }

        public void Close()
        {
            _isMeasuring = false;
            SetEvent();
            serialPort.DataReceived += OnDataReceived;
            if (serialPort.IsOpen)
            {
                dataReceived = null;
                try
                {
                    serialPort.Close();
                }
                catch (Exception ex)
                {
                    Log.WriteException(ex.ToString());
                }                
            }          
        }

        /// <summary>
        /// 打开/关闭激光
        /// </summary>
        /// <param name="open">true: 打开激光；off: 关闭激光</param>
        public void SetLaserOnOff(bool open)
        {
            if(!serialPort.IsOpen)
            {
                return;
            }
            if(open)
            {
                serialPort.WriteLine("iLD:1");
            }
            else
            {
                serialPort.WriteLine("iLD:0");
            }
        }

        /// <summary>
        /// 设置通讯协议
        /// </summary>
        /// <param name="mode"></param>
        public void SetProtocol(int mode)
        {
            if (!serialPort.IsOpen)
            {
                return;
            }
            serialPort.WriteLine($"iSET:4,{mode}");
        }

        /// <summary>
        /// 设置量程
        /// 单位: mm
        /// </summary>
        /// <param name="range"></param>
        public void SetRange(int range)
        {
            if (!serialPort.IsOpen)
            {
                return;
            }
            serialPort.WriteLine($"iSET:2,{range}");
        }

        public void DoSingleMeasure()
        {
            serialPort.WriteLine($"iSM");
        }

        public void StartWorking()
        {
            _isMeasuring = true;
            thread = new Thread(OnMeasuring);
            thread.Start();
            SetEvent();
        }

        public void StopWorking()
        {
            _isMeasuring = false;
            SetEvent();
        }

        /// <summary>
        /// 使等待事件获得信号, 恢复被暂停/阻塞的工作项任务
        /// </summary>
        public void SetEvent()
        {
            _waitEvent.Set();
        }

        /// <summary>
        /// 暂停/阻塞任务
        /// </summary>
        public void Wait()
        {
            _waitEvent.Reset();
        }

        private void OnMeasuring()
        {
            while (_isMeasuring)
            {
                _waitEvent.Wait();
                if (!_isMeasuring)
                    break;
                if (!serialPort.IsOpen)
                {
                    Log.Write("检测到串口已经被关闭，测量服务将被终止.");
                    break;
                }                                       
                try
                {
                    serialPort.WriteLine("iSM");
                }
                catch(Exception ex)
                {
                    Log.WriteException(ex.ToString());
                    continue;
                }               
                Thread.Sleep(_option.ScanInterval);
            }
        }

        private bool TryParseMeasuredResult(string dataReceived, out int result)
        {
            result = 0;
            if (string.IsNullOrEmpty(dataReceived))
            {
                return false;
            }
            if (dataReceived.Contains("OK"))
            {
                Log.Write("操作成功...");
                OnErrorReceived(dataReceived, 0);
                return false;
            }
            if (dataReceived.Contains("STOP"))
            {
                Log.Write("测量停止了...");
                OnErrorReceived(dataReceived, 0);
                return false;
            }
            if (dataReceived.Contains("LASER CLOSE"))
            {
                Log.Write("激光关闭了...");
                OnErrorReceived(dataReceived, 0);
                return false;
            }
            if (dataReceived.Contains("LASER OPEN"))
            {
                Log.Write("激光打开了...");
                OnErrorReceived(dataReceived, 0);
                return false;
            }
            if (dataReceived.StartsWith("E="))
            {
                int p0 = dataReceived.IndexOf('=');
                string code = dataReceived.Substring(p0 + 1, dataReceived.Length - p0 - 1);
                int val = 0;
                if (int.TryParse(code, out val))
                {
                    LaserErrorCode err = (LaserErrorCode)val;
                    _error = MapError[err];
                    Log.Write(_error);
                    OnErrorReceived(_error, val);
                }
                return false;
            }
            if (!dataReceived.Contains("D=") )
            {
                Log.Write(dataReceived);
                OnErrorReceived(dataReceived, 0);
                return false;
            }
            int start = dataReceived.IndexOf('=');
            int end = dataReceived.IndexOf('m');
            if(start < 0 || end < 0)
            {
                Log.Write(dataReceived);
                OnErrorReceived(dataReceived, 0);
                return false;
            }
            string distance = dataReceived.Substring(start + 1, end - start - 1);
            float value = 0.0f;
            if (float.TryParse(distance, out value))
            {
                result = (int)(value * 100 + 0.5);
                return true;
            }
            else
            {
                string strLog = string.Format("无法解析的结果:{0}", dataReceived);
                Log.Write(strLog);
                return false;
            }
        }

        public Dictionary<LaserErrorCode, string> MapError = new Dictionary<LaserErrorCode, string>();
        public void InitErrorMap()
        {
            MapError.Add(LaserErrorCode.DeviceError, "硬件异常");
            MapError.Add(LaserErrorCode.HEXCRCCheckError, "CUSTOM HEX协议校验错误");
            MapError.Add(LaserErrorCode.HEXFuncCodeError, "CUSTOM HEX协议功能码错误");
            MapError.Add(LaserErrorCode.HEXParamError, "CUSTOM HEX协议参数错误");
            MapError.Add(LaserErrorCode.HignReflex, "强反射");
            MapError.Add(LaserErrorCode.LaserTubeError, "激光管异常");
            MapError.Add(LaserErrorCode.OK, "正常");
            MapError.Add(LaserErrorCode.OverHeat, "温度过高");
            MapError.Add(LaserErrorCode.OverRange, "超出量程");
            MapError.Add(LaserErrorCode.PhotoSensorError, "光敏器件异常");
            MapError.Add(LaserErrorCode.TempLow, "温度过低");
            MapError.Add(LaserErrorCode.WeakReflex, "弱反射");          
        }
    }
}
